package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIoTConfigProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.vo.DeviceDataGraphVo;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.zzyl.vo.DeviceDataGraphVo.dayInstance;
import static com.zzyl.vo.DeviceDataGraphVo.weekInstance;

@Service
public class DeviceServiceImpl implements DeviceService {

    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;

    @Autowired
    private Client client;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private DeviceMapper deviceMapper;

    @Override
    public void syncProductList() {
        QueryProductListRequest queryProductListRequest = new QueryProductListRequest();
        queryProductListRequest.setPageSize(100);
        queryProductListRequest.setCurrentPage(1);
        queryProductListRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        QueryProductListResponse response = null;
        try {
            response = client.queryProductList(queryProductListRequest);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        if (response.getBody().getSuccess()) {
            List<QueryProductListResponseBody.QueryProductListResponseBodyDataListProductInfo> productInfo = response.getBody().getData().getList().getProductInfo();
            String jsonStr = JSONUtil.toJsonStr(productInfo);
            redisTemplate.opsForValue().set(CacheConstants.DEVICE_LIST, jsonStr);
        }
    }

    @Override
    public List<ProductVo> allProduct() {
        String s = redisTemplate.opsForValue().get(CacheConstants.DEVICE_LIST);
        return JSONUtil.toList(s, ProductVo.class);
    }

    @Override
    public void insert(DeviceDto deviceDto) {
        // 1.查询设备名称是否重复
        DeviceVo deviceVo = deviceMapper.queryByDeviceName(deviceDto.getDeviceName());
        if (ObjectUtil.isNotEmpty(deviceVo)) {
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }
        // 2.IOT新增设备
        RegisterDeviceRequest registerDeviceRequest = deviceDto.getRegisterDeviceRequest();
        registerDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        RegisterDeviceResponse response = null;
        try {
            response = client.registerDevice(registerDeviceRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }

        // 2.2 确认设备是否注册成功
        if (response == null || !response.getBody().success) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }

        // 3.查询产品名称，设置产品名称到设备对象
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        device.setIotId(response.getBody().getData().getIotId());
        //  3.1查询产品
        QueryProductRequest queryProductRequest = new QueryProductRequest();
        queryProductRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        queryProductRequest.setProductKey(deviceDto.getProductKey());
        QueryProductResponse queryProductResponse = null;
        try {
            queryProductResponse = client.queryProduct(queryProductRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR);
        }

        //  3.2 设置产品名称
        if (queryProductResponse.getBody().getSuccess()) {
            device.setProductName(queryProductResponse.getBody().getData().getProductName());
        }

        // 4.判断位置类型
        if (deviceDto.getLocationType() == 0) {
            device.setBindingLocation("-1");
        }

        // 5.插入数据库
        try {
            deviceMapper.insert(device);
        } catch (Exception e) {
            // 插入失败，删除IOT设备
            DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
            deleteDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
            deleteDeviceRequest.setProductKey(deviceDto.getProductKey());
            deleteDeviceRequest.setDeviceName(deviceDto.getDeviceName());
            DeleteDeviceResponse deleteDeviceResponse = null;
            try {
                deleteDeviceResponse = client.deleteDevice(deleteDeviceRequest);
            } catch (Exception ex) {
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
            if (!deleteDeviceResponse.getBody().getSuccess()) {
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
        }

    }

    @Override
    public PageResponse pageQueryDevice(DevicePageQueryDto devicePageQueryDto) {
        PageHelper.startPage(devicePageQueryDto.getPageNum(), devicePageQueryDto.getPageSize());
        Page<DeviceVo> page = deviceMapper.pageQueryDevice(devicePageQueryDto);
        return PageResponse.of(page, DeviceVo.class);
    }

    @Override
    public DeviceVo queryDeviceDetail(DeviceDto deviceDto) {
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        // 获取设备详情
        DeviceVo deviceVo = deviceMapper.queryDeviceDetail(device);
        // 获取设备数据
        QueryDeviceDetailRequest queryDeviceDetailRequest = new QueryDeviceDetailRequest();
        queryDeviceDetailRequest.setIotId(deviceDto.getIotId());
        queryDeviceDetailRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        queryDeviceDetailRequest.setProductKey(deviceDto.getProductKey());

        QueryDeviceDetailResponse queryDeviceDetailResponse = null;
        try {
            queryDeviceDetailResponse = client.queryDeviceDetail(queryDeviceDetailRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        if (!queryDeviceDetailResponse.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }

        // 整合数据
        BeanUtil.copyProperties(queryDeviceDetailResponse.getBody().getData(), deviceVo); // 修改: 将两个对象的数据进行合并
        return deviceVo;
    }

    @Override
    public QueryDevicePropertyStatusResponse queryDevicePropertyStatus(DeviceDto deviceDto) {
        QueryDevicePropertyStatusRequest request = new QueryDevicePropertyStatusRequest();
        request.setDeviceName(deviceDto.getDeviceName());
        request.setProductKey(deviceDto.getProductKey());
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        QueryDevicePropertyStatusResponse response = null;
        try {
            response = client.queryDevicePropertyStatus(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }

        if (!response.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }

        return response;
    }

    @Override
    public QueryThingModelPublishedResponse queryThingModelPublished(DeviceDto deviceDto) {
        QueryThingModelPublishedRequest request = new QueryThingModelPublishedRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        request.setProductKey(deviceDto.getProductKey());

        QueryThingModelPublishedResponse response = null;
        try {
            response = client.queryThingModelPublished(request);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (!response.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR);
        }

        return response;
    }

    @Override
    public void updateDevice(DeviceDto deviceDto) {
        // 1.修改IOT
        BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
        // 1.1 创建List集合
        List<BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo> deviceNicknameInfos = new ArrayList<>();
        // 1.2 创建对象
        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo deviceNicknameInfo = new BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo();
        // 1.3 设置参数
        deviceNicknameInfo.setNickname(deviceDto.getNickname());
        deviceNicknameInfo.setProductKey(deviceDto.getProductKey());
        deviceNicknameInfo.setDeviceName(deviceDto.getDeviceName());
        deviceNicknameInfo.setIotId(deviceDto.getIotId());

        // 1.4 添加到集合中
        deviceNicknameInfos.add(deviceNicknameInfo);
        // 1.5 设置request
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        request.setDeviceNicknameInfo(deviceNicknameInfos);
        // 1.6 发送请求
        BatchUpdateDeviceNicknameResponse response = null;
        try {
            response = client.batchUpdateDeviceNickname(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }
        // 1.7 判断
        if (!response.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }
        // 2.修改数据库
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        deviceMapper.updateDevice(device);
    }

    @Override
    public void deleteDevice(DeviceDto deviceDto) {
        // 1.删除IOT
        DeleteDeviceRequest request = new DeleteDeviceRequest();
        request.setIotId(deviceDto.getIotId());
        request.setProductKey(deviceDto.getProductKey());
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        DeleteDeviceResponse response = null;
        try {
            response = client.deleteDevice(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }

        if (!response.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }

        // 2.删除数据库
        deviceMapper.deleteById(deviceDto.getIotId());
    }

    @Override
    public List<DeviceDataGraphVo> queryDeviceDataListByDay(String iotId, String functionId, Long startTime, Long endTime) {
        LocalDateTime startDate = LocalDateTimeUtil.of(startTime);
        LocalDateTime endDate = LocalDateTimeUtil.of(endTime);
        List<DeviceDataGraphVo> list = deviceMapper.queryDeviceDataListByDay(iotId, functionId, startDate, endDate);
        List<DeviceDataGraphVo> deviceDataGraphVos = dayInstance(startDate);
        Map<String, Double> map = list.stream().collect(Collectors.toMap(DeviceDataGraphVo::getDateTime, DeviceDataGraphVo::getDataValue));
        deviceDataGraphVos.forEach(d -> {
            list.forEach(l -> {
                if (d.getDateTime().equals(l.getDateTime())){
                    if (l.getDataValue() != null){
                        d.setDataValue(l.getDataValue());
                    }else{
                        d.setDataValue(0.0);
                    }
                }
            });
        });
        return deviceDataGraphVos;
    }

    @Override
    public List<DeviceDataGraphVo> queryDeviceDataListByWeek(String iotId, String functionId, Long startTime, Long endTime) {
        LocalDateTime startDate = LocalDateTimeUtil.of(startTime);
        LocalDateTime endDate = LocalDateTimeUtil.of(endTime);
        List<DeviceDataGraphVo> list = deviceMapper.queryDeviceDataListByWeek(iotId, functionId, startDate, endDate);
        List<DeviceDataGraphVo> deviceDataGraphVos = weekInstance(startDate);
        Map<String, Double> map = list.stream().collect(Collectors.toMap(DeviceDataGraphVo::getDateTime, DeviceDataGraphVo::getDataValue));
        deviceDataGraphVos.forEach(d -> {
            list.forEach(l -> {
                if (d.getDateTime().equals(l.getDateTime())){
                    if (l.getDataValue() != null){
                        d.setDataValue(l.getDataValue());
                    }else{
                        d.setDataValue(0.0);
                    }
                }
            });
        });
        return deviceDataGraphVos;
    }
}
